package com.andong.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.andong.domain.entity.Coach;
import com.andong.domain.entity.Student;
import com.andong.domain.pojo.PageResult;
import com.andong.domain.pojo.Result;
import com.andong.domain.vo.StudentListVO;
import com.andong.service.StudentService;
import com.andong.utils.AliSMSUtils;
import com.andong.utils.BaseContext;
import com.andong.utils.CommonUtils;
import com.andong.utils.HmacSHA256Utils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.andong.domain.entity.RegisterBooking;
import com.andong.service.RegisterBookingService;
import com.andong.mapper.RegisterBookingMapper;
import com.baomidou.mybatisplus.extension.toolkit.Db;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.List;

import static com.andong.utils.SystemConstant.*;

/**
* @author 王海云
* @description 针对表【register_booking(学员预约注册表)】的数据库操作Service实现
* @createDate 2024-01-13 16:34:54
*/
@Service
public class RegisterBookingServiceImpl extends ServiceImpl<RegisterBookingMapper, RegisterBooking>
    implements RegisterBookingService{
    @Resource
    private AliSMSUtils aliSMSUtils;
    @Resource
    private StudentService studentService;
    @Resource
    private RedisTemplate<String, String> redisTemplate;
    @Override
    public Result add(RegisterBooking registerBooking, String code) throws Exception {
        String phone = registerBooking.getPhone();
        String username = registerBooking.getUsername();
        String idNumber = registerBooking.getIdNumber();
        // 1.校验验证码
        if (!aliSMSUtils.checkCode(phone, code)) {
            return Result.error(CODE_ERROR);
        }
        // 2.校验用户名是否存在以及是否合规(学员表和预约注册表)
        if (!username.startsWith(STUNDENT_ACCOUNT_PREFIX)) {
            return Result.error(ACCOUNT_START_WITH_S);
        }
        Student student = studentService.lambdaQuery()
                .eq(Student::getUsername, username)
                .one();
        RegisterBooking booking = lambdaQuery()
                .eq(RegisterBooking::getUsername, username)
                .ne(RegisterBooking::getStatus, REFUSED_REGISTER)
                .one();
        if (student != null || booking != null) {
            return Result.error(USERNAME_EXIST);
        }
        // 3.校验手机号
        student = studentService.lambdaQuery()
                .eq(Student::getPhone, phone)
                .one();
        booking = lambdaQuery()
                .eq(RegisterBooking::getPhone, phone)
                .ne(RegisterBooking::getStatus, REFUSED_REGISTER)
                .one();
        if (student != null || booking != null) {
            return Result.error(PHONE_BINDING);
        }
        // 校验身份证号
        student = studentService.lambdaQuery()
                .eq(Student::getIdNumber, idNumber)
                .one();
        booking = lambdaQuery()
                .eq(RegisterBooking::getIdNumber, idNumber)
                .ne(RegisterBooking::getStatus, REFUSED_REGISTER)
                .one();
        if (student != null || booking != null) {
            return Result.error(ID_BINDING);
        }
        // 校验年龄是否允许报考
        Integer age = CommonUtils.getAge(idNumber);
        Integer type = registerBooking.getLicenseType();
        if (!CommonUtils.checkAgeAndType(age, type)) {
            return Result.error(AGE_ERROR);
        }
        // 添加预约信息
        registerBooking.setAge(age);
        Integer gender = CommonUtils.getGender(idNumber);
        registerBooking.setGender(gender);
        // 密码加密
        String password = HmacSHA256Utils.calculateHmacSHA256(registerBooking.getPassword());
        registerBooking.setPassword(password);
        save(registerBooking);
        // 删除验证码缓存
        redisTemplate.delete(phone);
        return Result.success();
    }

    @Override
    @Transactional
    public Result updateStatus(Long id, Integer status) throws Exception {
        // 1.查询当前状态
        RegisterBooking booking = getById(id);
        Integer preStatus = booking.getStatus();
        if (status <= preStatus || !ALL_REGISTER_STATUS.contains(status)) {
            return Result.error(STATUS_ERROR);
        }
        // 2.更新状态
        booking.setStatus(status);
        updateById(booking);
        // 3.如果当前是已同意状态则将信息拷贝到学员表，并将结果以短信形式发送给用户
        if (status.equals(AGREE_REGISTER)) {
            // 拷贝属性
            Student student = BeanUtil.copyProperties
                    (booking, Student.class, "id", "status", "create_time", "update_time");
            // 添加学员
            studentService.save(student);
            // 发送短信通知用户
            aliSMSUtils.sendSuccess(student.getPhone(), student.getName());
            // 删除预约信息
            removeById(id);
            return Result.success();
        }
        if (status.equals(REFUSED_REGISTER)) {
            // 查询预约信息
            RegisterBooking registerBooking = getById(id);
            // 发送短信通知用户
            aliSMSUtils.sendFile(registerBooking.getPhone(), registerBooking.getName());
            // 删除预约信息
            removeById(id);
            return Result.success();
        }
        return Result.success();
    }

    @Override
    public PageResult queryList(Integer page, Integer pageSize, String name, Integer gender, Integer licenseType) {
        // 构造分页器
        Page<RegisterBooking> registerBookingPage = new Page<>(page, pageSize);
        // 构造Student条件查询器, 得到Student分页查询基本信息结果
        registerBookingPage = lambdaQuery()
                .like(name != null, RegisterBooking::getName, name)
                .eq(gender != null, RegisterBooking::getGender, gender)
                .eq(licenseType != null, RegisterBooking::getLicenseType, licenseType)
                .orderByAsc(RegisterBooking::getStatus)
                .page(registerBookingPage);
        // 使用stream流的方式对记录中的每一条数据进行处理
        List<RegisterBooking> records = registerBookingPage.getRecords();
        List<RegisterBooking> voList = records.stream().peek(recode -> recode.setPassword(null)).toList();
        return new PageResult(registerBookingPage.getTotal(), voList);
    }
}




